package com.centerm.bluetooth.ibridge;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;

import com.centerm.bluetooth.ibridge.listener.ConnectionReceiver;
import com.centerm.util.Logger;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;

final class ConnectionListener {
    private static final String TAG = "ConnectionListener";
    private BluetoothAdapter mAdapter;
    private ConnectionReceiver mReceiver;
    private AcceptThread mThread;
    private boolean mAuthenticated;

    public ConnectionListener(ConnectionReceiver receiver, boolean auth) {
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mReceiver = receiver;
        mAuthenticated = auth;
    }

    public void start() {
        if (mThread != null) {
            mThread.cancel();
        }
        mThread = new AcceptThread();
        mThread.start();
    }

    public void stop() {
        if (mThread != null) {
            mThread.cancel();
        }
    }

    private class AcceptThread extends Thread {
        // The local server socket
        private static final String SERVICE_NAME = "Bluetooth-IBridge";
        private final BluetoothServerSocket mmServerSocket;
        private volatile boolean running;

        public AcceptThread() {
            BluetoothServerSocket tmp = null;
            running = true;
            // Create a new listening server socket
            try {
                if (!mAuthenticated) {
                    tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(SERVICE_NAME, BluetoothIBridgeDevice.SPPUUID);
                    //listenUsingInsecureRfcommWithServiceRecord(SERVICE_NAME, BluetoothIBridgeDevice.SPPUUID);
                    BluetoothIBridgeAdapter.log("InsecureRfcomm+++++++" + tmp);
                } else {
                    tmp = mAdapter.listenUsingRfcommWithServiceRecord(SERVICE_NAME, BluetoothIBridgeDevice.SPPUUID);
                    BluetoothIBridgeAdapter.log("SecureRfcomm+++++++" + tmp);
                }
            } catch (IOException e) {
                Logger.e(TAG, e, "Connection listen() failed");
            }
            mmServerSocket = tmp;
        }

        public void run() {
            Logger.d(TAG, "BEGIN mAcceptThread");
            setName("AcceptThread");

            BluetoothSocket socket = null;

            // Listen to the server socket if we're not connected
            while (running) {
                try {
                    // This is a blocking call and will only return on a
                    // successful connection or an exception
                    if (mmServerSocket == null) {
                        return;
                    }
                    socket = mmServerSocket.accept();
                } catch (IOException e) {
                    Logger.i(TAG, e, "accept() failed");
                    break;
                }

                // If a connection was accepted
                if (socket != null) {
                    if (mReceiver != null) {
                        mReceiver.onConnectionEstablished(socket);
                    }
                }
            }
            Logger.i(TAG, "END mAcceptThread");

        }

        public void cancel() {
            Logger.d(TAG, "cancel " + this);
            try {
                if (null != mmServerSocket) {
                    mmServerSocket.close();
                    Logger.i(TAG, "mmServerSocket closed");
                }
            } catch (IOException e) {
                Logger.e(TAG, e, "close() of server failed");
            }
        }

        private BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String serviceName, UUID serviceUUID) {
            BluetoothServerSocket socket = null;
            try {
                Class<? extends BluetoothAdapter> cls = BluetoothAdapter.class;
                Method m = cls.getMethod("listenUsingInsecureRfcommWithServiceRecord", String.class, UUID.class);
                socket = (BluetoothServerSocket) m.invoke(mAdapter, serviceName, serviceUUID);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            return socket;
        }
    }

    void setLinkKeyNeedAuthenticated(boolean authenticated) {
        if (mAuthenticated != authenticated) {
            mAuthenticated = authenticated;
            stop();
            start();
        }
    }
}
